﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using Seagull.Configuration;
using Seagull.Generic;
using Seagull.Model.Alerts;

namespace Seagull.Alerts
{
    public class HistoryAlerts
    {
        private static readonly XmlSerializer _xmlSerializer = new XmlSerializer(typeof (HistoryAlerts));

        private static readonly object _syncRoot = new object();

        internal HistoryAlerts()
        {
            Alerts = new List<GenericAlert>();
        }

        public List<GenericAlert> Alerts { get; set; }

        private static HistoryAlerts LoadOrCreate()
        {
            try
            {
                using(var fileStream = FileHelper.Open(() =>
                    File.OpenRead(Config.Instance.PathConfig.AlertFileName)))
                {
                    return (HistoryAlerts)_xmlSerializer.Deserialize(fileStream);
                }
            }
            catch (Exception exception)
            {
                if (
                    exception is FileNotFoundException || 
                    exception is InvalidOperationException || 
                    exception is DirectoryNotFoundException)
                {
                    return CreateNew();
                }
                throw;
            }
        }

        private static HistoryAlerts CreateNew()
        {
            var directory = Path.GetDirectoryName(Config.Instance.PathConfig.AlertFileName);
            if (!string.IsNullOrEmpty(directory))
            {
                Directory.CreateDirectory(directory);
            }
            var historyAlerts = new HistoryAlerts();
            historyAlerts.Save();
            return historyAlerts;
        }

        public static void Change(Action<HistoryAlerts> change)
        {
            lock (_syncRoot)
            {
                var historyAlerts = LoadOrCreate();
                change(historyAlerts);
                historyAlerts.Save();
            }
        }

        public static T Change<T>(Func<HistoryAlerts, T> change)
        {
            lock (_syncRoot)
            {
                var historyAlerts = LoadOrCreate();
                var result = change(historyAlerts);
                historyAlerts.Save();
                return result;
            }
        }

        public static T Read<T>(Func<HistoryAlerts, T> read)
        {
            lock (_syncRoot)
            {
                var historyAlerts = LoadOrCreate();
                return read(historyAlerts);
            }
        }

        private void Save()
        {
            using(var fileStream = FileHelper.Open(() =>
                File.Open(Config.Instance.PathConfig.AlertFileName,
                    FileMode.Create, FileAccess.Write, FileShare.None)))
            {
                _xmlSerializer.Serialize(fileStream, this);
            }
        }
    }
}